/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "default_job_queue.h"
#include "log.h"

namespace ImageKnifePro {

int IJobQueue::GetUniqueJobId()
{
    static int id = 0;
    id++;
    return id;
}

ImageSource *GetImageSrc(std::shared_ptr<ImageKnifeOption> option, ImageRequestType type)
{
    ImageSource *data = nullptr;
    switch (type) {
        case ImageRequestType::MAIN_SRC:
            data = &option->loadSrc;
            break;
        case ImageRequestType::PLACE_SRC:
            data = &option->placeholderSrc;
            break;
        case ImageRequestType::THUMBNAIL_SRC:
            data = &option->thumbnailSrc;
            break;
        case ImageRequestType::ERROR_SRC:
            data = &option->errorSrc;
            break;
        default:
            break;
    }

    if (data != nullptr && data->GetType() == DataType::UNDEFINED) {
        return nullptr;
    }

    return data;
}

IJobQueue::Job::Job(std::shared_ptr<ImageKnifeRequestInternal> request, ImageRequestType type,
    std::string memoryKey, int traceId) : request(request), type(type), memoryKey(memoryKey), jobId(traceId)
{
    IMAGE_KNIFE_CHECK(request == nullptr);
    if (type == ImageRequestType::MAIN_SRC) {
        auto option = request->GetImageKnifeOption();
        IMAGE_KNIFE_CHECK(option == nullptr);
        if (option->writeCacheStrategy == CacheStrategy::FILE || option->writeCacheStrategy == CacheStrategy::NONE) {
            // 不写内存缓存
            writeMemoryCache = false;
            auto preloadType = request->GetPreloadType();
            if (preloadType == ImageKnifeRequestInternal::PreloadType::PRELOAD ||
                preloadType == ImageKnifeRequestInternal::PreloadType::PRELOAD_FILE) {
                phase = EndPhase::LOADING;
            }
        }
    }
}

IJobQueue::Job::Job(std::shared_ptr<ImageKnifeRequestInternal> request, ImageRequestType type)
    : request(request), type(type), jobId(GetUniqueJobId())
{
    IMAGE_KNIFE_CHECK(request == nullptr);
    auto option = request->GetImageKnifeOption();
    IMAGE_KNIFE_CHECK(option == nullptr);
    imageSrc = GetImageSrc(option, type);
    if (imageSrc == nullptr) {
        if (type == ImageRequestType::THUMBNAIL_SRC) {
            request->MarkThumbnailSrcUnavailable();
        }
        return;
    }

    loadingKey = imageSrc->ToString();
    if (imageSrc->GetType() == DataType::RESOURCE && option->context.config != nullptr) {
        loadingKey += ";" + std::to_string(option->context.config->colorMode);
    }

    if (type == ImageRequestType::MAIN_SRC) {
        if (!option->signature.empty()) {
            loadingKey += ";" + option->signature;
        }

        if (option->writeCacheStrategy == CacheStrategy::MEMORY || option->writeCacheStrategy == CacheStrategy::NONE) {
            // 不写文件缓存
            writeFileCache = false;
        }

        if (option->writeCacheStrategy == CacheStrategy::FILE || option->writeCacheStrategy == CacheStrategy::NONE) {
            // 不写内存缓存
            writeMemoryCache = false;
            auto preloadType = request->GetPreloadType();
            if (preloadType == ImageKnifeRequestInternal::PreloadType::PRELOAD ||
                preloadType == ImageKnifeRequestInternal::PreloadType::PRELOAD_FILE) {
                phase = EndPhase::LOADING;
            }
        }
    }
}

size_t DefaultJobQueue::GetQueueLength()
{
    std::lock_guard<std::mutex> guard(queueLock_);
    return highQueue_.size() + highQueue_.size() + normalQueue_.size() + lowQueue_.size();
}

void DefaultJobQueue::Add(Job job)
{
    IMAGE_KNIFE_CHECK(job.request == nullptr, "NUll ImageKnifeRequest");
    std::lock_guard<std::mutex> guard(queueLock_);
    if (job.type == ImageRequestType::PLACE_SRC) {
        placeholder_.push(job);
        return;
    }

    if (job.request->GetImageKnifeOption()->priority == Priority::HIGH) {
        highQueue_.push(job);
    } else if (job.request->GetImageKnifeOption()->priority == Priority::MEDIUM) {
        normalQueue_.push(job);
    } else {
        lowQueue_.push(job);
    }
}

DefaultJobQueue::Job DefaultJobQueue::Pop()
{
    std::lock_guard<std::mutex> guard(queueLock_);
    if (!placeholder_.empty()) {
        return PopFromQueue(placeholder_);
    }

    if (!highQueue_.empty()) {
        return PopFromQueue(highQueue_);
    }

    if (!normalQueue_.empty()) {
        return PopFromQueue(normalQueue_);
    }

    if (!lowQueue_.empty()) {
        return PopFromQueue(lowQueue_);
    }

    return Job{};
}

DefaultJobQueue::Job DefaultJobQueue::PopFromQueue(std::queue<Job> &queue)
{
    Job job = queue.front();
    queue.pop();
    return job;
}

}